package com.dag.account.service.impl;

import com.dag.account.api.dto.refund.RefundRecordDTO;
import com.dag.account.api.dto.refund.UnifiedRefundReqDTO;
import com.dag.account.api.dto.refund.UnifiedRefundRespDTO;
import com.dag.account.constants.*;
import com.dag.account.dao.entity.Account;
import com.dag.account.dao.entity.Member;
import com.dag.account.dao.entity.TradeRecord;
import com.dag.account.service.*;
import com.dag.account.utils.TradeUtils;
import com.dag.common.exception.BusinessRuntimeException;
import com.dag.common.utils.ModelMapperUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 退款管理
 * @author 孙建
 * @since 2020-06-01
 */
@Slf4j
@Service
public class RefundServiceImpl implements IRefundService {

    @Autowired
    private IMemberService memberService;
    @Autowired
    private ITradeRecordService tradeRecordService;
    @Autowired
    private IFundPoolService fundPoolService;
    @Autowired
    private IPlatformService platformService;
    @Autowired
    private IAccountService accountService;

    /**
     * 统一退款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UnifiedRefundRespDTO unifiedRefund(UnifiedRefundReqDTO refundRequestDTO) {
        String refundMemberId = refundRequestDTO.getRefundMemberId();
        Integer accountType = refundRequestDTO.getAccountType();
        String operatorName = refundRequestDTO.getOperatorName();
        // 退款人和退款账户
        Account refundAccount = accountService.queryByMemberIdAndAccountType(refundMemberId, accountType);
        Member refundMember = memberService.getById(refundMemberId);
        // 平台账户
        Account platformAccount = platformService.queryPlatformAccount();
        Member platformMember = platformService.queryPlatformMember();

        // 查询之前支付的记录
        TradeRecord payTradeRecord = tradeRecordService.queryBySerialNo(refundRequestDTO.getSerialNo());

        // 校验账户
        UnifiedRefundRespDTO refundResponseDTO = validateUnifiedRefund(refundRequestDTO, refundAccount, payTradeRecord);
        // 校验通过
        if(refundResponseDTO.isSuccess()){
            BigDecimal refundMoney = refundRequestDTO.getAmount();
            // 平台账户减钱
            accountService.deduction(platformAccount, refundMoney, operatorName);
            // 退款账户加钱
            accountService.add(refundAccount, refundMoney, operatorName);
            // 保存退款交易记录
            TradeRecord tradeRecord = new TradeRecord();
            tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
            tradeRecord.setTradeVoucherNo(refundRequestDTO.getTradeVoucherNo());
            tradeRecord.setAccountId(refundMember.getId());
            tradeRecord.setMemberId(refundMember.getId());
            tradeRecord.setMemberName(refundMember.getMemberName());
            tradeRecord.setOtherMemberId(platformMember.getId());
            tradeRecord.setOtherMemberName(platformMember.getMemberName());
            tradeRecord.setOtherAccountId(platformAccount.getId());
            tradeRecord.setTradeType(TradeTypeEnum.REFUND.getIndex());
            tradeRecord.setTradeTypeName(TradeTypeEnum.REFUND.getText());
            tradeRecord.setAmount(refundMoney);
            tradeRecord.setTradeChannel(TradeChannelEnum.ACCOUNT.getIndex());
            tradeRecord.setTradeSubject(refundRequestDTO.getTradeSubject());
            tradeRecord.setTradeContent(payTradeRecord.getTradeContent());
            tradeRecord.setFundFlowType(FundFlowTypeEnum.INCOME.getIndex());
            tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
            Date date = new Date();
            tradeRecord.setCreateTime(date);
            tradeRecord.setTradeTime(date);
            tradeRecord.setOrgId(platformAccount.getOrgId());
            tradeRecord.setMerchantId(platformAccount.getMerchantId());
            // 生成平台交易记录
            TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(tradeRecord);
            tradeRecordService.saveBatch(Lists.newArrayList(tradeRecord, otherTradeRecord));

            // 退款成功返回信息
            refundResponseDTO.setSerialNo(tradeRecord.getSerialNo());
            refundResponseDTO.setAmount(refundMoney);
            refundResponseDTO.setMessage("退款成功");
        }
        return refundResponseDTO;
    }

    /**
     * 退款记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundRecord(RefundRecordDTO refundRecordDTO) {
        String tradeVoucherNo = refundRecordDTO.getTradeVoucherNo();
        String operatorName = refundRecordDTO.getOperatorName();
        TradeRecord payTradeRecord = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo,
                TradeTypeEnum.PAYED.getIndex(), FundFlowTypeEnum.PAY.getIndex(), TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        if(payTradeRecord == null){
            throw new BusinessRuntimeException("未找到支付记录");
        }

        // 判断退款金额是否相等
        BigDecimal amount = refundRecordDTO.getAmount();
        if(payTradeRecord.getAmount().abs().compareTo(amount.abs()) != 0){
            throw new BusinessRuntimeException("退款金额不一致");
        }

        Member member = memberService.getById(payTradeRecord.getMemberId());
        if(member == null){
            throw new BusinessRuntimeException("付款会员不存在");
        }

        // 平台收款账户减去一笔
        Account platformAccount = platformService.queryPlatformAccount();
        Member platformMember = platformService.queryPlatformMember();
        accountService.deduction(platformAccount, amount, operatorName);

        // 资金池减去一笔
        fundPoolService.deduction(amount, operatorName);

        // 保存交易记录
        TradeRecord refundTradeRecord = ModelMapperUtils.map(refundRecordDTO, TradeRecord.class);
        refundTradeRecord.setSerialNo(TradeUtils.buildSeqNo());
        refundTradeRecord.setMemberId(member.getId());
        refundTradeRecord.setMemberName(member.getMemberName());
        refundTradeRecord.setAccountId(payTradeRecord.getMemberId());
        refundTradeRecord.setOtherMemberId(platformMember.getId());
        refundTradeRecord.setOtherMemberName(platformMember.getMemberName());
        refundTradeRecord.setOtherAccountId(platformAccount.getId());
        refundTradeRecord.setTradeType(TradeTypeEnum.REFUND.getIndex());
        refundTradeRecord.setTradeTypeName(TradeTypeEnum.REFUND.getText());
        refundTradeRecord.setAmount(amount);
        refundTradeRecord.setTradeChannel(payTradeRecord.getTradeChannel());
        refundTradeRecord.setTradeSubject(refundRecordDTO.getTradeSubject());
        refundTradeRecord.setTradeContent(refundRecordDTO.getTradeContent());
        refundTradeRecord.setFundFlowType(FundFlowTypeEnum.INCOME.getIndex());
        refundTradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        refundTradeRecord.setCreateTime(new Date());
        refundTradeRecord.setOrgId(member.getOrgId());
        refundTradeRecord.setMerchantId(member.getMerchantId());

        // 生成平台交易记录
        TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(refundTradeRecord);
        tradeRecordService.saveBatch(Lists.newArrayList(refundTradeRecord, otherTradeRecord));
    }

    /**
     * 退款校验
     */
    private UnifiedRefundRespDTO validateUnifiedRefund(UnifiedRefundReqDTO refundRequestDTO, Account refundAccount, TradeRecord payTradeRecord) {
        String tradeVoucherNo = refundRequestDTO.getTradeVoucherNo();
        if(refundAccount == null){
            return UnifiedRefundRespDTO.byFail(null, tradeVoucherNo, "退款账户不存在");
        }

        if(payTradeRecord == null){
            return UnifiedRefundRespDTO.byFail(null, tradeVoucherNo, "未查询到支付流水");
        }

        // 判断交易是否已经操作过
        TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo, TradeTypeEnum.REFUND.getIndex(),
                FundFlowTypeEnum.INCOME.getIndex(), TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        if(tradeRecord != null){
            return UnifiedRefundRespDTO.byFail(tradeRecord.getSerialNo(), tradeVoucherNo, "交易业务单号已完成交易，请检查");
        }

        Integer draweeAccountStatus = refundAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return UnifiedRefundRespDTO.byFail(null, tradeVoucherNo, "退款账户状态异常");
        }

        BigDecimal payAmount = payTradeRecord.getAmount().abs();
        BigDecimal refundAmount = refundRequestDTO.getAmount().abs();
        if(refundAmount.compareTo(payAmount) > 0){
            return UnifiedRefundRespDTO.byFail(null, tradeVoucherNo, "退款金额不能超过实际支付金额");
        }
        return UnifiedRefundRespDTO.bySuccess(null, tradeVoucherNo, "校验通过");
    }

}
